你我應該都有類似的不佳體驗:點下一個按鈕時,畫面什麼也沒有改變,你以為剛剛沒點到,又再點了一次,發現還是沒反應,開始感到有點生氣。接下來的動作因人而異,可能會重載畫面、繼續等下去、打給客服、發出某種四聲的單詞...正在考慮的時候,這時候畫面突然通知你:「你的XX已經完成」。這時突然有一種「莊孝維...」,剛剛我是被耍了嗎...的感覺。
雖然只是缺少一個小小的「忙碌中」訊息提示,但是卻可能造成系統很大影響,例如因為沒回應,很多人會多點一次,而這種耗時的動作通常比較消耗系統資源(消耗較多計算力或記憶體),每個人都多點一次反而造成系統更慢、更無法回應。另一種等不及的人總是會重載畫面,可能兩次之後就放棄你的程式,或是打爆客服的電話,增加額外的處理成本。
為了避免使用者這種不好的感覺,ZK 預設內建「請等待」訊息。當元件送出的 AJAX request 在 900ms 內沒有收到回應,就會自動根據瀏覽器語言顯示一個「處理中」訊息,並配有轉圈圈動畫。
這個行為不需要任何設定,只要你傾聽器程式在伺服器端執行過久,讓瀏覽器等超過 900ms,ZK 就會幫你在左上角顯示這個訊息,給予使用者明確的回饋。
<button label="耗時動作" onClick="doLongOperation()"/>
<zscript><![CDATA[
public doLongOperation(){
org.zkoss.lang.Threads.sleep(3000); //模擬一個耗時的動作
}
]]></zscript>
如果你認為你的網路環境較慢,可以在 zk.xml
調整預設等待時間,請看 The processing-prompt-delay Element。
如果你覺得忙碌訊息不要在左上角,也可以設定調整位置,請看 org.zkoss.zul.progressbox.position
如果你希望不只顯示訊息而是要遮罩著整個畫面,以免使用者再點其他的按鈕,可啟用設定:org.zkoss.zk.ui.processMask.enabled
如果你想要顯示別的訊息,可覆寫以下 js 變數:
<script defer="true"><![CDATA[
msgzk.PLEASE_WAIT = "進行中";
]]></script>
請參考 ZK_Developer's_Reference/Internationalization/Warning_and_Error_Messages
你也許覺得只顯示「處理中」有點無趣,希望能能更大幅度的變化 UI 來顯示進行中。例如原本是這樣:
當按下按鈕之後會變色且文字改變:
初步你會把按鈕變色與耗時動作寫在同一個 onClick listener:
button.addSclass("busy");
button.setLabel("進行中...");
doLongOperation();
但你會發現耗時動作做完了才變色。因為點下按鈕後,送出AU request 並等待 listener 執行完回來,才能取得元件對 js widget 的更新,這樣就無法在進行耗時動作前就變色,因此要分成兩個 listener:
但豈不是要按兩次按鈕去呼叫兩次 listener,多奇怪啊! 因此有一個方法可以在第一個 listener 中呼叫第二個 listener 的方法: Echo event:
細部流程如下:
程式碼如下:
<button label="送出" autodisable="self" >
<attribute name="onClick">
self.addSclass("busy");
self.setLabel("進行中...");
Events.echoEvent("onLongOperation", self, null); //送出一個自訂 echo event
</attribute>
<attribute name="onLongOperation">
doLongOperation();
self.removeSclass("busy");
self.setLabel("送出");
</attribute>
</button>
<zscript><![CDATA[
public doLongOperation(){
org.zkoss.lang.Threads.sleep(3000); //模擬一個耗時的動作
}
]]></zscript>
<style>
.busy{
background-color: orange;
}
</style>